package com.kh.rationaldrugreview.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kh.rationaldrugreview.dto.EntityMatchResult;
import com.kh.rationaldrugreview.entity.KnowledgeEntity;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 * LLM实体匹配服务
 * 使用大语言模型进行智能实体匹配
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LLMEntityMatcher {
    
    private final ChatClient chatClient;
    private final KnowledgeEntityService knowledgeEntityService;
    private final ObjectMapper objectMapper;
    
    // Prompt模板
    private static final String ENTITY_MATCH_PROMPT = """
        你是一个医药领域的实体匹配专家。请帮我识别以下输入是否指向某个特定的医药实体。
        
        输入名称: {inputName}
        实体类型: {entityType}
        
        已知的候选实体列表：
        {candidateList}
        
        请分析输入名称，考虑以下因素：
        1. 药品可能的通用名、商品名、别名
        2. 可能的拼写错误或输入法错误
        3. 缩写或简称
        4. 中英文混合
        5. 剂型后缀（如"片"、"胶囊"等）
        
        请返回JSON格式的匹配结果：
        {
            "matched": true/false,
            "entityName": "匹配到的标准实体名称",
            "canonicalName": "规范化名称",
            "confidence": 0.0-1.0,
            "reasoning": "匹配理由",
            "alternativeNames": ["其他可能的名称"],
            "suggestions": ["如果未匹配，提供可能的建议"]
        }
        
        注意：
        - 如果确信匹配，confidence应该>=0.85
        - 如果不太确定，confidence应该在0.5-0.85之间
        - 如果无法匹配，matched为false，confidence为0
        - reasoning要简洁明了，说明匹配的依据
        """;
    
    private static final String CONTEXT_MATCH_PROMPT = """
        你是一个医药领域的实体识别专家。用户描述了一个药品或疾病，请帮我识别具体是什么。
        
        用户描述: {description}
        上下文信息: {context}
        实体类型: {entityType}
        
        请根据描述和上下文，推断用户指的是哪个具体的医药实体。
        
        返回JSON格式：
        {
            "matched": true/false,
            "entityName": "推断的实体名称",
            "confidence": 0.0-1.0,
            "reasoning": "推断依据",
            "needsConfirmation": true/false,
            "candidates": ["可能的候选1", "可能的候选2"]
        }
        """;
    
    /**
     * LLM匹配结果
     */
    @Data
    private static class LLMMatchResponse {
        private Boolean matched;
        private String entityName;
        private String canonicalName;
        private Double confidence;
        private String reasoning;
        private List<String> alternativeNames;
        private List<String> suggestions;
        private Boolean needsConfirmation;
        private List<String> candidates;
    }
    
    /**
     * 使用LLM进行实体匹配
     */
    public EntityMatchResult matchWithLLM(String inputName, String entityType, 
                                         List<EntityMatchResult.CandidateEntity> traditionalCandidates) {
        long startTime = System.currentTimeMillis();
        
        try {
            // 准备候选列表
            String candidateList = prepareCandidateList(traditionalCandidates);
            
            // 构建prompt
            String prompt = ENTITY_MATCH_PROMPT
                .replace("{inputName}", inputName)
                .replace("{entityType}", translateEntityType(entityType))
                .replace("{candidateList}", candidateList);
            
            // 调用LLM
            String response = chatClient.prompt()
                .user(prompt)
                .call()
                .content();
            
            long responseTime = System.currentTimeMillis() - startTime;
            
            // 解析响应
            LLMMatchResponse llmResponse = parseLLMResponse(response);
            
            // 构建匹配结果
            return buildMatchResult(inputName, entityType, llmResponse, responseTime, response);
            
        } catch (Exception e) {
            log.error("LLM matching failed for input: {}", inputName, e);
            return handleLLMError(inputName, entityType, e);
        }
    }
    
    /**
     * 使用LLM进行上下文匹配
     */
    public EntityMatchResult matchWithContext(String description, Map<String, Object> context, String entityType) {
        long startTime = System.currentTimeMillis();
        
        try {
            // 构建上下文字符串
            String contextStr = context != null ? objectMapper.writeValueAsString(context) : "{}";
            
            // 构建prompt
            String prompt = CONTEXT_MATCH_PROMPT
                .replace("{description}", description)
                .replace("{context}", contextStr)
                .replace("{entityType}", translateEntityType(entityType));
            
            // 调用LLM
            String response = chatClient.prompt()
                .user(prompt)
                .call()
                .content();
            
            long responseTime = System.currentTimeMillis() - startTime;
            
            // 解析响应
            LLMMatchResponse llmResponse = parseLLMResponse(response);
            
            // 构建匹配结果
            return buildMatchResult(description, entityType, llmResponse, responseTime, response);
            
        } catch (Exception e) {
            log.error("Context matching failed for description: {}", description, e);
            return handleLLMError(description, entityType, e);
        }
    }
    
    /**
     * 准备候选列表字符串
     */
    private String prepareCandidateList(List<EntityMatchResult.CandidateEntity> candidates) {
        if (candidates == null || candidates.isEmpty()) {
            return "暂无候选实体";
        }
        
        StringBuilder sb = new StringBuilder();
        int count = 0;
        for (EntityMatchResult.CandidateEntity candidate : candidates) {
            if (count >= 10) break; // 限制候选数量
            
            sb.append(String.format("%d. %s (标准名: %s, 相似度: %.2f)\n",
                ++count,
                candidate.getEntityName(),
                candidate.getCanonicalName(),
                candidate.getSimilarity()
            ));
        }
        
        return sb.toString();
    }
    
    /**
     * 翻译实体类型
     */
    private String translateEntityType(String entityType) {
        return switch (entityType) {
            case "DRUG" -> "药品";
            case "DISEASE" -> "疾病";
            case "SYMPTOM" -> "症状";
            case "PATIENT_PROFILE" -> "患者特征";
            case "ADVERSE_REACTION" -> "不良反应";
            default -> entityType;
        };
    }
    
    /**
     * 解析LLM响应
     */
    private LLMMatchResponse parseLLMResponse(String response) {
        try {
            // 提取JSON部分
            String json = extractJson(response);
            return objectMapper.readValue(json, LLMMatchResponse.class);
        } catch (Exception e) {
            log.warn("Failed to parse LLM response, using fallback", e);
            
            // 降级处理：简单解析
            LLMMatchResponse fallback = new LLMMatchResponse();
            fallback.setMatched(false);
            fallback.setConfidence(0.0);
            fallback.setReasoning("LLM响应解析失败");
            return fallback;
        }
    }
    
    /**
     * 从响应中提取JSON
     */
    private String extractJson(String response) {
        // 查找JSON开始和结束
        int start = response.indexOf("{");
        int end = response.lastIndexOf("}");
        
        if (start != -1 && end != -1 && end > start) {
            return response.substring(start, end + 1);
        }
        
        // 尝试查找```json标记
        if (response.contains("```json")) {
            start = response.indexOf("```json") + 7;
            end = response.indexOf("```", start);
            if (end > start) {
                return response.substring(start, end).trim();
            }
        }
        
        return response;
    }
    
    /**
     * 构建匹配结果
     */
    private EntityMatchResult buildMatchResult(String originalName, String entityType, 
                                              LLMMatchResponse llmResponse, 
                                              long responseTime, String rawResponse) {
        
        EntityMatchResult.LLMReasoning llmReasoning = EntityMatchResult.LLMReasoning.builder()
            .model("gpt-3.5-turbo")
            .response(rawResponse)
            .responseTimeMs(responseTime)
            .reasoning(llmResponse.getReasoning())
            .build();
        
        EntityMatchResult.MatchDetails details = EntityMatchResult.MatchDetails.builder()
            .llmReasoning(llmReasoning)
            .matchingSteps(List.of("LLM智能匹配"))
            .build();
        
        // 如果LLM匹配成功，尝试查找对应的实体
        if (Boolean.TRUE.equals(llmResponse.getMatched()) && llmResponse.getEntityName() != null) {
            KnowledgeEntity entity = knowledgeEntityService.findEntity(entityType, llmResponse.getEntityName());
            
            if (entity != null) {
                return EntityMatchResult.builder()
                    .originalName(originalName)
                    .matchedEntity(entity)
                    .canonicalName(entity.getCanonicalName())
                    .entityId(entity.getEntityId())
                    .entityType(entityType)
                    .matchType(EntityMatchResult.MatchType.LLM)
                    .algorithm(EntityMatchResult.MatchAlgorithm.GPT_35)
                    .confidence(llmResponse.getConfidence())
                    .needsConfirmation(llmResponse.getConfidence() < 0.85)
                    .details(details)
                    .processingTimeMs(responseTime)
                    .matchedAt(LocalDateTime.now())
                    .build();
            }
        }
        
        // 构建候选列表
        List<EntityMatchResult.CandidateEntity> candidates = new ArrayList<>();
        if (llmResponse.getCandidates() != null) {
            for (String candidateName : llmResponse.getCandidates()) {
                KnowledgeEntity candidateEntity = knowledgeEntityService.findEntity(entityType, candidateName);
                if (candidateEntity != null) {
                    candidates.add(EntityMatchResult.CandidateEntity.builder()
                        .entityId(candidateEntity.getEntityId())
                        .entityName(candidateEntity.getEntityName())
                        .canonicalName(candidateEntity.getCanonicalName())
                        .entityType(candidateEntity.getEntityType())
                        .similarity(0.5)
                        .matchReason("LLM推荐")
                        .build());
                }
            }
        }
        
        // 返回未匹配结果
        EntityMatchResult notFound = EntityMatchResult.notFound(originalName, entityType);
        notFound.setDetails(details);
        notFound.setCandidates(candidates.isEmpty() ? null : candidates);
        notFound.setProcessingTimeMs(responseTime);
        
        return notFound;
    }
    
    /**
     * 处理LLM错误
     */
    private EntityMatchResult handleLLMError(String originalName, String entityType, Exception error) {
        log.error("LLM matching error for '{}': {}", originalName, error.getMessage());
        
        EntityMatchResult result = EntityMatchResult.notFound(originalName, entityType);
        result.setErrorMessage("LLM匹配失败: " + error.getMessage());
        result.setNeedsConfirmation(true);
        
        return result;
    }
    
    /**
     * 批量LLM匹配（优化token使用）
     */
    public List<EntityMatchResult> batchMatchWithLLM(Map<String, String> nameToTypeMap) {
        // 批量处理以减少API调用
        List<EntityMatchResult> results = new ArrayList<>();
        
        for (Map.Entry<String, String> entry : nameToTypeMap.entrySet()) {
            results.add(matchWithLLM(entry.getKey(), entry.getValue(), null));
        }
        
        return results;
    }
}